#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "lvgl.h"
#include "esp_log.h"
#include "st7789_driver.h"
#include "driver/gpio.h"
#include "esp_timer.h"

#include "button.h"
#include "keysound.h"

/*
1.初始化和注册LVGL显示驱动
2.初始化ST7789硬件接口
3.提供一个定时器给LVGL使用
*/

#define TAG     "lv_port"

// #define LCD_WIDTH       170
// #define LCD_HEIGHT      320
#define LCD_WIDTH       ST7789_WIDTH
#define LCD_HEIGHT      ST7789_HEIGHT

static lv_disp_drv_t    disp_drv;

lv_indev_t * indev_keypad;
lv_group_t * group;

static bool editing = false;  // 用于标志当前为编辑状态还是导航状态

bool is_editing(void){
    return editing;
}

void set_editing(const bool value){
    editing = value;
}


void lv_flush_done_cb(void* param)
{
    lv_disp_flush_ready(&disp_drv);
}

void disp_flush(struct _lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
    st7789_flush(area->x1,area->x2 + 1,area->y1+20,area->y2+20 + 1,color_p);
}

void lv_disp_init(void)
{
    static lv_disp_draw_buf_t   disp_buf;
    // const size_t disp_buf_size = LCD_WIDTH*(LCD_HEIGHT/7);
    const size_t disp_buf_size = LCD_WIDTH*(LCD_HEIGHT/7);  // 2

    lv_color_t *disp1 = heap_caps_malloc(disp_buf_size*sizeof(lv_color_t),MALLOC_CAP_INTERNAL|MALLOC_CAP_DMA);
    lv_color_t *disp2 = heap_caps_malloc(disp_buf_size*sizeof(lv_color_t),MALLOC_CAP_INTERNAL|MALLOC_CAP_DMA);
    if(!disp1 || !disp2)
    {
        ESP_LOGE(TAG,"disp buff malloc fail!");
        return;
    }
    lv_disp_draw_buf_init(&disp_buf, disp1, disp2, disp_buf_size);

    lv_disp_drv_init(&disp_drv);

    disp_drv.hor_res = LCD_WIDTH;
    disp_drv.ver_res = LCD_HEIGHT;
    disp_drv.draw_buf = &disp_buf;
    disp_drv.flush_cb = disp_flush;
    lv_disp_drv_register(&disp_drv);
}

/*Get the currently being pressed key.  0 if no key is pressed*/
static uint32_t keypad_get_key(void)
{
    /*Your code comes here*/
    uint32_t btnCode = btnScan();
    switch (btnCode)
    {
    case 1:
        // 横屏按键
        // if (is_editing()) {  // 处于编辑状态
        //     // ESP_LOGI(TAG,"处于编辑状态  pre!");
        //     return 3;
        // } else {
        //     return 2;
        // }
        // 竖屏按键
        if (is_editing()) {  // 处于编辑状态
            // ESP_LOGI(TAG,"处于编辑状态  pre!");
            return 4;
        } else {
            return 1;
        }
        // return 2;
        break;
    
    case 2:
        // 横屏按键
        // if (is_editing()) {  // 处于编辑状态
        //     // ESP_LOGI(TAG,"处于编辑状态  next!");
        //     return 4;
        // } else {
        //     return 1;
        // }
        // 竖屏按键
        if (is_editing()) {  // 处于编辑状态
            // ESP_LOGI(TAG,"处于编辑状态  pre!");
            return 3;
        } else {
            return 2;
        }
        // return 1;
        break;
    
    case 3:
        return 5;
        break;
    
    default:
        return 0;
        break;
    }
    return 0;
}


/*Will be called by the library to read the mouse*/
static void keypad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
    static uint32_t last_key = 0;

    /*Get the current x and y coordinates*/
    // mouse_get_xy(&data->point.x, &data->point.y);

    /*Get whether the a key is pressed and save the pressed key*/
    uint32_t act_key = keypad_get_key();
    if(act_key != 0) {
        data->state = LV_INDEV_STATE_PR;
        startPlay();
        /*Translate the keys to LVGL control characters according to your key definitions*/
        switch(act_key) {
            case 1:
                act_key = LV_KEY_NEXT;
                // act_key = LV_KEY_RIGHT;
                ESP_LOGI(TAG,"LV_KEY_NEXT!");
                break;
            case 2:
                act_key = LV_KEY_PREV;
                // act_key = LV_KEY_LEFT;
                ESP_LOGI(TAG,"LV_KEY_PREV!");
                break;
            case 3:
                act_key = LV_KEY_LEFT;
                // act_key = LV_KEY_PREV;
                break;
            case 4:
                act_key = LV_KEY_RIGHT;
                // act_key = LV_KEY_NEXT;
                break;
            case 5:
                act_key = LV_KEY_ENTER;
                ESP_LOGI(TAG,"LV_KEY_ENTER!");
                break;
        }

        last_key = act_key;
    }
    else {
        data->state = LV_INDEV_STATE_REL;
    }

    data->key = last_key;
}

/*Initialize your keypad*/
static void keypad_init(void)
{
    /*Your code comes here*/
    initBtn();
}
void lv_indev_init(void)
{
    static lv_indev_drv_t indev_drv;
    keypad_init();
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_KEYPAD;
    indev_drv.read_cb = keypad_read;
    indev_keypad = lv_indev_drv_register(&indev_drv);

    group = lv_group_create();
    lv_indev_set_group(indev_keypad, group);
}


lv_group_t* get_group(void)
{
    return group;
}



void st7789_hw_init(void)
{
    st7789_cfg_t st7789_config = {
        .bl = GPIO_NUM_14,
        .clk = GPIO_NUM_12,
        .cs = GPIO_NUM_10,
        .dc = GPIO_NUM_11,
        .mosi = GPIO_NUM_13,
        .rst = GPIO_NUM_1,
        .spi_fre = 40*1000*1000,
        .height = LCD_HEIGHT,
        .width = LCD_WIDTH,
        .spin = 0,
        .done_cb = lv_flush_done_cb,
        .cb_param = &disp_drv,
    };

    st7789_driver_hw_init(&st7789_config);
}


void lv_timer_cb(void* arg)
{
    uint32_t tick_interval = *((uint32_t*)arg);
    lv_tick_inc(tick_interval);
}

void lv_tick_init(void)
{
    static uint32_t tick_interval = 5;
    const esp_timer_create_args_t arg = 
    {
        .arg = &tick_interval,
        .callback = lv_timer_cb,
        .name = "",
        .dispatch_method = ESP_TIMER_TASK,
        .skip_unhandled_events = true,
    };

    esp_timer_handle_t timer_handle;
    esp_timer_create(&arg,&timer_handle);
    esp_timer_start_periodic(timer_handle,tick_interval*1000);
}

void lv_port_init(void)
{
    lv_init();
    st7789_hw_init();
    lv_disp_init();
    lv_indev_init();
    lv_tick_init();
}
